#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <vector>
#include <unistd.h>
#include <string>
#include <sstream>
//#include <comoobjapi.h>
#include <comoapi.h>
#include <comoobj.h>
#include "DebugUtils.h"

using namespace std;

std::vector<string> split(const string& str, char delimiter)
{
    std::vector<string> tokens;
    string token;
    std::stringstream ss(str);

    while (std::getline(ss, token, delimiter)) {
        tokens.push_back(token);
    }

    return tokens;
}

void GetFileNames(string path, vector<string>& filenames)
{
    DIR *pDir;
    struct dirent* ptr;
    if (! (pDir = opendir(path.c_str())))
        return;
    while ((ptr = readdir(pDir)) != 0) {
        if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
            string filename = ptr->d_name;
            string suffixStr = filename.substr(filename.find_last_of('.') + 1);
            if (suffixStr.compare("so") == 0) {
                filenames.push_back(path + "/" + ptr->d_name);
            }
        }
    }
    closedir(pDir);
}

string GetFileNameFromPath(const string& fullPath)
{
    size_t pos = fullPath.find_last_of("/\\");
    if (pos == string::npos) {
        return fullPath;
    }
    return fullPath.substr(pos + 1);
}

int main(int argc, char *argv[])
{
    vector<string> paths;
    char *env = getenv("LIB_PATH");

    if (nullptr != env) {
        paths = split(string(env), ':');
    }
    else {
        char* cwd = getcwd(nullptr, 0);
        if (nullptr != cwd) {
            paths.push_back(string(cwd));
            free(cwd);
        }
    }

    vector<string> file_names;
    for (const string& path : paths) {
        GetFileNames(path, file_names);
    }

    AutoPtr<IClassLoader> loader;
    ECode ec = CoGetBootClassLoader(loader);

    for (int i = 0; i < file_names.size(); i++) {
        AutoPtr<IMetaComponent> component;

        Logger::D("", "Try to load COMO component: %s", file_names[i].c_str());
        ec = loader->LoadComponent(como::String(file_names[i].c_str()), component);
        if (FAILED(ec)) {
            continue;
        }

        como::String name;
        ec = component->GetName(name);
        string tmpStr = GetFileNameFromPath(file_names[i]);

        component->Unload();

        const char *strComoMoudle = name.string();
        const char *strFilePath = tmpStr.c_str();
        int lenComoMoudle = strlen(strComoMoudle);
        int lenFilePath = strlen(strFilePath);
        bool stdComoComponentName = true;

        if ((strncmp(strComoMoudle, strFilePath, lenComoMoudle) == 0) &&
                                                    (lenFilePath > lenComoMoudle)) {
            if ('.' == strFilePath[lenComoMoudle]) {
                for (int i = lenComoMoudle + 1;  i < lenFilePath;  i++) {
                    if (('/' == strFilePath[i]) || ('\\' == strFilePath[i])) {
                        stdComoComponentName = false;
                        break;
                    }
                }
            }
            else {
                stdComoComponentName = false;
            }
        } else {
            stdComoComponentName = false;
        }

        if (! stdComoComponentName) {
            Logger::D("", "Non-standard COMO component file name, "
                           "module name: \"%s\", component file name: \"%s\"",
                           strComoMoudle, strFilePath);
        }
    }

    return 0;
}
